package com.sloan.community.controller;

import com.sloan.community.po.User;
import com.sloan.community.provider.GitHubProvider;
import com.sloan.community.provider.GiteeProvider;
import com.sloan.community.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.server.WebSession;
import reactor.core.publisher.Mono;

import java.time.Duration;

import static com.sloan.community.common.Constant.Oauth2.GITEE;
import static com.sloan.community.common.Constant.Oauth2.GITHUB;
import static com.sloan.community.common.Constant.SESSION_USER;

@Slf4j
@Controller
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class LoginController {

    private final GitHubProvider gitHubProvider;

    private final GiteeProvider giteeProvider;

    private final UserService userService;

    @Value("${server.reactive.session.cookie.name}")
    private String cookieName;

    @Value("${server.reactive.session.cookie.path}")
    private String cookiePath;

    @Value("${server.reactive.session.cookie.domain}")
    private String cookieDomain;

    @Value("${oauth2.gitee.client_id}")
    private String giteeClientId;

    @Value("${oauth2.github.client_id}")
    private String githubClientId;

    @Value("${oauth2.gitee.redirect_url}")
    private String giteeRedirectUrl;

    @Value("${oauth2.github.redirect_url}")
    private String githubRedirectUrl;


    @GetMapping("logout")
    public Mono<String> logout(WebSession session, ServerHttpResponse response) {
        session.getAttributes().remove(SESSION_USER);

        ResponseCookie cookie = ResponseCookie.from(cookieName)
                .maxAge(Duration.ZERO)
                .path(cookiePath)
                .domain(cookieDomain)
                .build();
        response.addCookie(cookie);
        return Mono.just("redirect:/");
    }

    @GetMapping("login.html")
    public Mono<String> login(@RequestHeader(value = "msg", required = false) String msg,
                              Model model) {
        if (StringUtils.hasText(msg)) {
            model.addAttribute("msg", msg);
        }
        model.addAttribute("gitee_client_id",giteeClientId);
        model.addAttribute("github_client_id",githubClientId);
        model.addAttribute("gitee_redirect_uri",giteeRedirectUrl);
        model.addAttribute("github_redirect_uri",githubRedirectUrl);
        return Mono.just("login");
    }

    @GetMapping("/login/oauth2/gitee/callback")
    public Mono<String> giteeCallback(@RequestParam("code") String code,
                                      WebSession webSession) {
        Mono<User> userMono = giteeProvider.fetchUserInfo(code)
                .map(gitee -> {
                    User user = new User();
                    user.setOuth2UserId(String.valueOf(gitee.getId()));
                    user.setUsername(gitee.getLogin());
                    user.setNickname(gitee.getName());
                    user.setEmail(gitee.getEmail());
                    user.setAvatarUrl(gitee.getAvatar_url());
                    user.setAddress(gitee.getHtml_url());
                    return user;
                });
        return userService.saveOrUpdate(userMono, GITEE.getCode())
                .doOnNext(user -> webSession.getAttributes().put(SESSION_USER, user))
                .map(user -> "redirect:/");
    }


    /**
     * 重定向返回以下几种都可以
     * ① Mono<Rendering> Rendering build = Rendering.redirectTo("/").build();
     * ② Mono<RedirectView> RedirectView view = new RedirectView(redirectUri.toString());
     * ③ Mono<String> Mono.just("redirect:/")
     * ④ response.getHeaders().setLocation(URI.create("/login.html")); response.setComplete();
     */
    @GetMapping("/login/oauth2/github/callback")
    public Mono<String> githubCallback(@RequestParam("code") String code, @RequestParam("state") String state,
                                       WebSession webSession) {
        Mono<User> userMono = gitHubProvider.fetchUserInfo(code)
                .map(github -> {
                    User user = new User();
                    user.setOuth2UserId(String.valueOf(github.getId()));
                    user.setUsername(github.getLogin());
                    user.setNickname(github.getName());
                    user.setEmail(github.getEmail());
                    user.setAvatarUrl(github.getAvatar_url());
                    user.setAddress(github.getLocation());
                    user.setAddress(github.getHtml_url());
                    return user;
                });
        return userService.saveOrUpdate(userMono, GITHUB.getCode())
                .doOnNext(user -> {
                    webSession.getAttributes().put(SESSION_USER, user);
                }).flatMap(user -> Mono.just("redirect:/"));
    }

}
